package algo3.algothief.vista;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import java.io.BufferedReader;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.xml.sax.SAXException;

import algo3.algothief.excepcion.CasoAunEnCursoException;
import algo3.algothief.excepcion.CasoNoIniciadoException;
import algo3.algothief.excepcion.NombreDelJugadorNoDefinidoException;
import algo3.algothief.excepcion.PaisInvalidoParaViajarDesdeElActualException;
import algo3.algothief.excepcion.LugarInvalidoParaVisitarDesdeEPaislActualException;
import algo3.algothief.modelo.Juego;


public class VistaJuego {
	
	private VistaInicioDelJuego vistaDelInicioDelJuego;
	
	private Juego juego;
	
	private VistaTiempo vistaDelTiempo;
	private VistaPolicia vistaDelPolicia;
	private VistaCaso vistaDelCaso;
	
//---------------------------------------------------------------------------------------------------------
	
	public VistaJuego(Juego juegoAMostrar) {
		this.vistaDelInicioDelJuego = new VistaInicioDelJuego();
		
		this.juego = juegoAMostrar;
		
		this.vistaDelTiempo = new VistaTiempo(juego);
		this.vistaDelPolicia = new VistaPolicia(juego);
		this.vistaDelCaso = new VistaCaso(juego);
	}
	
//---------------------------------------------------------------------------------------------------------
	
	private void borrarLaPantalla() {
		for (int i = 0; i < 42; i++)
			System.out.println();
	}
	
	private void tiempoDeEsperaEntreDialogos(int miliSegundos) {
		try {
		    Thread.sleep(miliSegundos);
		} catch(InterruptedException ex) {
		    Thread.currentThread().interrupt();
		}
	}
	
	private void graficarMensajeIntermedioEntreMensajes(BufferedReader entradaDeTeclado) throws IOException {
		System.out.println("(Presione enter para continuar)");
		entradaDeTeclado.readLine();
	}
	
	

	
	private void graficarOpcionDelMenu(String indiceDeLaOpcion, String nombreDelLugar) {
		System.out.println("     " + indiceDeLaOpcion + ")" + nombreDelLugar); 
	}
	
	
	
	private void graficarMensajeDePistasIncorrectas(){
		System.out.println("Las pistas proporcionadas eliminan a todos los");
		System.out.println("posibles sopechosos!\n");
		
		this.tiempoDeEsperaEntreDialogos(500);
		
		System.out.println("No se ha emitido una orden de arresto.");
	}

	private void graficarSospechososQueConcuerdanConLaDescripcionHechaPorElJugador(ArrayList<String> nombresDeLosSospechosos) {
		System.out.println("Sospechosos:");
		
		for (String nombreDelSospechoso : nombresDeLosSospechosos) 
			System.out.println("-" + nombreDelSospechoso);
		
		int cantidadDeSospechosos = nombresDeLosSospechosos.size();
		if (cantidadDeSospechosos == 1) {
			System.out.println("\nOrden de arresto emitida contra:");
			System.out.println(nombresDeLosSospechosos.get(0) + ".");
		}
	}
	
//---------------------------------------------------------------------------------------------------------
	
	public static void graficarMensajeDeError(ParserConfigurationException excepcion) {
		VistaError.graficarMensajeDeError(excepcion);
	}
	
	public static void graficarMensajeDeError(SAXException excepcion) {
		VistaError.graficarMensajeDeError(excepcion);
	}
	
	public static void graficarMensajeDeError(IOException excepcion) {
		VistaError.graficarMensajeDeError(excepcion);
	}
	
	public static void graficarMensajeDeError(TransformerException excepcion) {
		VistaError.graficarMensajeDeError(excepcion);
	}
	
	public static void graficarMensajeDeError(PaisInvalidoParaViajarDesdeElActualException excepcion){
		VistaError.graficarMensajeDeError(excepcion);
	}
	
	public static void graficarMensajeDeError(LugarInvalidoParaVisitarDesdeEPaislActualException excepcion){
		VistaError.graficarMensajeDeError(excepcion);
	}
	
	public static void graficarMensajeDeError(CasoNoIniciadoException excepcion) {
		VistaError.graficarMensajeDeError(excepcion);
	}
	
	public static void graficarMensajeDeError(CasoAunEnCursoException excepcion) {
		VistaError.graficarMensajeDeError(excepcion);
	}
	
	public static void graficarMensajeDeError(NombreDelJugadorNoDefinidoException excepcion) {
		VistaError.graficarMensajeDeError(excepcion);
	}
	
	
	
	public static void graficarMensajeDeOpcionElegidaIncorrecta(BufferedReader entradaDeTeclado) throws IOException {
		VistaError.graficarMensajeDeOpcionElegidaIncorrecta(entradaDeTeclado);
	}
	
//---------------------------------------------------------------------------------------------------------	
	
	public void graficarMensajeDeInicioDelJuego() {
		VistaTransicion.graficarMensajeInicial();
	}
	
	public void graficarMensajeParaIdentificarAlJugador() {
		vistaDelInicioDelJuego.graficarMensajeParaIdentificarAlJugador();
	}
	
	public void graficarMensajeParaIdentificacionExitosa(String nombre) {
		vistaDelInicioDelJuego.graficarMensajeParaIdentificacionExitosa(nombre);
	}
	
	public void graficarMenuParaVerificarSiNoEstaIdentificadoElJugador() {
		vistaDelInicioDelJuego.graficarMenuParaVerificarSiNoEstaIdentificadoElJugador();
	}
	
	public void graficarMensajeParaReintentarLaIdentificacionDelJugador() {
		vistaDelInicioDelJuego.graficarMensajeParaReintentarLaIdentificacionDelJugador();
	}

//---------------------------------------------------------------------------------------------------------
	
	public void graficarMensajeDeGraduacionDelJugador(BufferedReader entradaDeTeclado)throws IOException {
		vistaDelPolicia.graficarMensajeDeGraduacionDelJugador(entradaDeTeclado);
	}

//---------------------------------------------------------------------------------------------------------
	
	public void graficarMensajeDeIntroduccionAlCaso(BufferedReader entradaDeTeclado) throws IOException, CasoNoIniciadoException {
		vistaDelCaso.graficarMensajeDeIntroduccionAlCaso(entradaDeTeclado);
		
		vistaDelTiempo.graficarMensajeDeTiempoLimiteParaElArresto();
		
		this.tiempoDeEsperaEntreDialogos(500);
		
		vistaDelPolicia.graficarMensajeAlentadorParaIniciarElCaso(juego.verElNombreDelJugador());
		
		this.tiempoDeEsperaEntreDialogos(500);
		this.graficarMensajeIntermedioEntreMensajes(entradaDeTeclado);
	}
	
	
	
	public void graficarMensajeDeHeridaDeBala(BufferedReader entradaDeTeclado) throws IOException {
		VistaTransicion.graficarTransicionDeHeridaDeBala();
		this.graficarMensajeIntermedioEntreMensajes(entradaDeTeclado);
	}
	
	public void graficarMensajeDeHeridaDeCuchillo(BufferedReader entradaDeTeclado) throws IOException {
		VistaTransicion.graficarTransicionDeHeridaDeCuchillo();
		this.graficarMensajeIntermedioEntreMensajes(entradaDeTeclado);
	}
	
	
	public void graficarMensajeDeCasoGanado(BufferedReader entradaDeTeclado) throws IOException {
		VistaTransicion.graficarTransicionDeCasoGanado();
		this.graficarMensajeIntermedioEntreMensajes(entradaDeTeclado);
	}
	
	public void graficarMensajeDeCasoPerdido(BufferedReader entradaDeTeclado) throws IOException {
		VistaTransicion.graficarTransicionDeCasoPerdido();
		this.graficarMensajeIntermedioEntreMensajes(entradaDeTeclado);
	}
	
	
	public void graficarMensajeDeSeAcaboElTiempo(BufferedReader entradaDeTeclado) throws IOException {
		VistaTransicion.graficarTransicionDeSeAcaboElTiempo();
		this.graficarMensajeIntermedioEntreMensajes(entradaDeTeclado);
	}
	
	
	
	public void graficarMensajeDeFinalizacionDelCaso(BufferedReader entradaDeTeclado, boolean seGanoElCaso, String nombreDelLadron) throws IOException {
		if (seGanoElCaso)
			vistaDelPolicia.graficarMensajeDeCasoGanado(entradaDeTeclado, nombreDelLadron);
		else
			vistaDelPolicia.graficarMensajeDeCasoPerdido(entradaDeTeclado, nombreDelLadron);
		
		this.tiempoDeEsperaEntreDialogos(500);
		
		System.out.println("Quiere comenzar otro caso?");
		System.out.println("(S/N)"); 
	}
	
//---------------------------------------------------------------------------------------------------------

	public void graficarMenuDeAccionesEnElJuego(HashMap<String, String> opcionesDelJuego) throws CasoNoIniciadoException {	
		this.borrarLaPantalla();
		
		vistaDelPolicia.graficarElNombreDeLaCapitalDelPaisDondeEsta();
		
		vistaDelTiempo.graficarLaFechaYLaHoraActuales();
		
		vistaDelPolicia.graficarLaDescripcionDelPaisDondeEsta();
		vistaDelTiempo.graficarMensajeDeCuantoTiempoQueda();
		
		this.tiempoDeEsperaEntreDialogos(500);
		
		System.out.println("Que quieres hacer ahora?\n");
			
		for (Entry<String, String> opcion : opcionesDelJuego.entrySet()) {
			String opcionElegible = opcion.getKey();
			String opcionVisible = opcion.getValue();
			
			System.out.println("     " + opcionElegible + ")" + opcionVisible);
		}	
			
		System.out.println("\n(ingrese uno de los numeros indicados)");
		System.out.println("(ingresando 0 podra retroceder al menu anterior siempre");
		System.out.println(" hasta llegar a este)");
	}
	
	
	
	public void graficarMenuDePosiblesPaisesParaViajar(HashMap<String, String> opcionesParaViajar) throws CasoNoIniciadoException {
		this.borrarLaPantalla();
		
		VistaTransicion.graficarMapaDelMundo();
		
		vistaDelPolicia.graficarMensajeDeUbicacionEnElMundo();
		
		System.out.println("Elige alguno de los siguientes destinos:\n");
		
		for (Entry<String, String> opcion : opcionesParaViajar.entrySet()) {
			String opcionElegible = opcion.getKey();
			String nombreDelPais = opcion.getValue();
			
			this.graficarOpcionDelMenu(opcionElegible, nombreDelPais);
		}	
		
		System.out.println("\n(ingrese uno de los numeros indicados)");
		System.out.println("(ingrese 0 para volver al menu anterior)");
	}
	
	public void seViajoAOtroPais() throws CasoNoIniciadoException {
		String nombreDeLaCapitalDelDestino = juego.verElNombreDelPaisActual();
		VistaTransicion.graficarTransicionEntreViajes(nombreDeLaCapitalDelDestino);
	}
	
	
	
	public void graficarMenuDePosiblesLugaresParaVisitar(HashMap<String, String> opcionesParaVisitar) {
		this.borrarLaPantalla();
		
		System.out.println("Elige alguno de los siguientes lugares:\n");
		
		for (Entry<String, String> opcion : opcionesParaVisitar.entrySet()) {
			String opcionElegible = opcion.getKey();
			String nombreDelLugar = opcion.getValue();
			
			this.graficarOpcionDelMenu(opcionElegible, nombreDelLugar);
		}	
		
		System.out.println("\n(ingrese uno de los numeros indicados)");
		System.out.println("(ingrese 0 para volver al menu anterior)");
	}
	
	public void graficarMensajeConPistaParaElJugador(String pista, BufferedReader entradaDeTeclado) throws IOException {
		this.borrarLaPantalla();
		
		VistaPista.graficarMensajeConPistaParaElJugador(pista, entradaDeTeclado);
	}
	
	
	
	public void graficarMenuDeEmisionDeOrdenDeArresto(HashMap<String, String> opcionesParaOrdenarUnArresto) {
		this.borrarLaPantalla();
		
		System.out.println("Elige alguna de las siguientes opciones:\n");
		
		for (Entry<String, String> opcion : opcionesParaOrdenarUnArresto.entrySet()) {
			String opcionElegible = opcion.getKey();
			String descripcionDeLaOpcion = opcion.getValue();
			
			this.graficarOpcionDelMenu(opcionElegible, descripcionDeLaOpcion);
		}	
		
		System.out.println("\n(ingrese uno de los numeros indicados)");
		System.out.println("(ingrese 0 para volver al menu anterior)");
	}
	
	public void graficarResultadoDeLaEmisionDeLaOrdenDeArresto(ArrayList<String> nombresDeLosSospechosos, BufferedReader entradaDeTeclado) throws IOException {
		VistaTransicion.graficarTransicionDeEmitiendoOrdenDeArresto();
		
		int cantidadDeSospechosos = nombresDeLosSospechosos.size();
		
		if (cantidadDeSospechosos == 0) 
			this.graficarMensajeDePistasIncorrectas();
		else 
			this.graficarSospechososQueConcuerdanConLaDescripcionHechaPorElJugador(nombresDeLosSospechosos);
			
		this.graficarMensajeIntermedioEntreMensajes(entradaDeTeclado);
	}
	
	
	public void graficarDescripcionDelSospechosoActual(ArrayList<String[]> caracteristicas) {
		this.borrarLaPantalla();
		
		System.out.println("||------------------------------------------||");
		System.out.println("|| Descripcion recopilada hasta el momento: ||");
		System.out.println("||------------------------------------------||\n");
		
		for (String[] caracteristica : caracteristicas) {
			String nombreDeLaCaracteristica = caracteristica[0];
			String descripcionDeLaCaracteristica = caracteristica[1];
			if (descripcionDeLaCaracteristica == null)
				descripcionDeLaCaracteristica = "";
			
			System.out.println("-" + nombreDeLaCaracteristica + ": " + descripcionDeLaCaracteristica);
		}	
		
		this.tiempoDeEsperaEntreDialogos(250);
	}
	
	public void graficarMenuDeModificacionDeLaDescripcionDelSospechoso(HashMap<String, String> opcionesParaModificarLaDescripcion) {
		System.out.println("\nElige alguna de las siguientes caracteristicas para");
		System.out.println("modificar:\n");
		
		for (Entry<String, String> opcion : opcionesParaModificarLaDescripcion.entrySet()) {
			String opcionElegible = opcion.getKey();
			String caracteristicaModificable = opcion.getValue();
			
			this.graficarOpcionDelMenu(opcionElegible, caracteristicaModificable);
		}	
		
		System.out.println("\n(ingrese uno de los numeros indicados)");
		System.out.println("(ingrese 0 para volver al menu anterior)");
	}
	
	public void graficarMenuDeEleccionDeNuevaCaracteristica(HashMap<String, String> opcionesParaModificarLaCaracteristica) {
		System.out.println("\nElige alguna de las siguientes opciones:\n");
		
		for (Entry<String, String> opcion : opcionesParaModificarLaCaracteristica.entrySet()) {
			String opcionElegible = opcion.getKey();
			String caracteristicaModificable = opcion.getValue();
			
			this.graficarOpcionDelMenu(opcionElegible, caracteristicaModificable);
		}	
		
		System.out.println("\n(ingrese uno de los numeros indicados)");
		System.out.println("(la ultima opcion es solo para volver a dejar");
		System.out.println(" vacia a la caracteristica)");
		System.out.println("(ingrese 0 para volver al menu anterior)");
	}
	
	
	
	public void graficarMensajeDePartidaGuardada(BufferedReader entradaDeTeclado) throws IOException {
		VistaTransicion.graficarTransicionDePartidaGuardandose();
		
		System.out.println("La partida ha sido guardada existosamente.");
		
		this.tiempoDeEsperaEntreDialogos(500);
		this.graficarMensajeIntermedioEntreMensajes(entradaDeTeclado);
	}
	
	
	
	public void graficarMensajeParaObtenerElNombreDelJugadorCuyaPartidaFueGuardada() {
		this.borrarLaPantalla();
		
		System.out.println("Ingrese el nombre del jugador con el que se guardo");
		System.out.println("la partida que desea cargar:");
	}
	
	public void graficarMensajeDePartidaInexistente(String nombreDelJugador, BufferedReader entradaDeTeclado) throws IOException {
		VistaTransicion.graficarTransicionDePartidaCargandose();
		
		System.out.println("No se ha podido encontrar una partida con el nombre");
		System.out.println("de " + nombreDelJugador + ".");
		
		this.tiempoDeEsperaEntreDialogos(500);
		this.graficarMensajeIntermedioEntreMensajes(entradaDeTeclado);
	}
	
	public void graficarMensajeDePartidaCargada(BufferedReader entradaDeTeclado) throws IOException {
		VistaTransicion.graficarTransicionDePartidaCargandose();
		
		System.out.println("La partida ha sido cargada exitosamente.");
		
		this.tiempoDeEsperaEntreDialogos(500);
		this.graficarMensajeIntermedioEntreMensajes(entradaDeTeclado);
	}
}
